package org.javaqq.face.main.screen;

import java.awt.AWTException;
import java.awt.Cursor;
import java.awt.Frame;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JOptionPane;

import org.apache.log4j.Logger;
import org.javaqq.face.util.SwingWorker;

public class Screenshot {
	private ImageSelectionPanel selectionPanel;
	private Robot robot;
	private BufferedImage bufferedImage;
	private static final Logger logger = Logger.getLogger(Screenshot.class);

	public Screenshot() {
		try {
			robot = new Robot();
			selectionPanel = new ImageSelectionPanel();
		} catch (AWTException e) {
			logger.error(e);
		}
	}

	/**
	 * Returns an image if one is found in the clipboard, otherwise null is
	 * returned.
	 * 
	 * @return the image in the clipboard if found, otherwise null.
	 */
	public static BufferedImage getClipboard() {
		Transferable t = Toolkit.getDefaultToolkit().getSystemClipboard()
				.getContents(null);

		try {
			if (t != null && t.isDataFlavorSupported(DataFlavor.imageFlavor)) {
				return (BufferedImage) t
						.getTransferData(DataFlavor.imageFlavor);
			}
		} catch (UnsupportedFlavorException e) {
			// Nothing to do
		} catch (IOException e) {
			// Nothing to do
		}
		return null;
	}

	public BufferedImage CreateScreenshot() {

		final SwingWorker worker = new SwingWorker() {
			public Object construct() {
				try {
					Thread.sleep(1000);
					Rectangle area = new Rectangle(Toolkit.getDefaultToolkit()
							.getScreenSize());
					return robot.createScreenCapture(area);
				} catch (Throwable e) {
					logger.error(e);
				}
				return null;
			}

			public void finished() {
				synchronized (this) {
					bufferedImage = (BufferedImage) get();
					if (bufferedImage == null) {
						JOptionPane.showMessageDialog(null,
								"Unable to process screenshot.",
								"Unable to process screenshot.",
								JOptionPane.ERROR_MESSAGE);
						return;
					}

					final Frame frame = new Frame();
					frame.setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));

					selectionPanel.setImage(bufferedImage);
					selectionPanel.validate();
					selectionPanel.addMouseListener(new MouseAdapter() {
						public void mouseReleased(MouseEvent e) {
							Rectangle clip = selectionPanel.getClip();
							BufferedImage newImage = null;
							try {
								newImage = bufferedImage.getSubimage((int) clip
										.getX(), (int) clip.getY(), (int) clip
										.getWidth(), (int) clip.getHeight());
							} catch (Exception e1) {
								// Nothing to do
							}

							if (newImage != null) {
								bufferedImage = newImage;
								selectionPanel.clear();
							}
							frame.dispose();
							frame.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
							selectionPanel.removeMouseListener(this);
							notify();
						}
					});

					frame.addKeyListener(new KeyAdapter() {
						public void keyReleased(KeyEvent e) {
							if (e.getKeyChar() == KeyEvent.VK_ESCAPE) {
								frame.dispose();
								frame.setCursor(new Cursor(
										Cursor.DEFAULT_CURSOR));
								notify();
							}
						}
					});

					frame.setSize(bufferedImage.getWidth(null), bufferedImage
							.getHeight());
					frame.add(selectionPanel);
					frame.setUndecorated(true);
					// Determine if full-screen mode is supported directly
					GraphicsEnvironment ge = GraphicsEnvironment
							.getLocalGraphicsEnvironment();
					GraphicsDevice gs = ge.getDefaultScreenDevice();
					if (gs.isFullScreenSupported()) {
						gs.setFullScreenWindow(frame);
					} else {
						// Full-screen mode will be simulated
						frame.setVisible(true);
					}
				}
			}
		};
		worker.start();
		synchronized (worker) {
			try {
				worker.wait();
				return bufferedImage;
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				return null;
			}
		}

	}

	public BufferedImage CreateScreenshotToClipboard() {
		BufferedImage bufferImage = null;
		try {
			bufferImage = CreateScreenshot();
			setClipboardImage(bufferImage);
		} catch (Exception ex) {
		}
		return bufferImage;
	}

	protected static void setClipboardImage(final Image image) {
		Transferable trans = new Transferable() {
			public DataFlavor[] getTransferDataFlavors() {
				return new DataFlavor[] { DataFlavor.imageFlavor };
			}

			public boolean isDataFlavorSupported(DataFlavor flavor) {
				return DataFlavor.imageFlavor.equals(flavor);
			}

			public Object getTransferData(DataFlavor flavor)
					throws UnsupportedFlavorException, IOException {
				if (isDataFlavorSupported(flavor))
					return image;
				throw new UnsupportedFlavorException(flavor);
			}

		};
		Toolkit.getDefaultToolkit().getSystemClipboard().setContents(trans,
				null);
	}

	public File ImageToFile(final BufferedImage image, final File imageFile) {

		SwingWorker writeImageThread = new SwingWorker() {

			public Object construct() {
				synchronized (this) {
					try {
						// Write out file in separate thread.
						ImageIO.write(image, "png", imageFile);
					} catch (IOException e) {
						logger.error(e);
					}
					notify();
					return true;

				}
			}

			public void finished() {
			}
		};
		writeImageThread.start();
		synchronized (writeImageThread) {
			try {
				writeImageThread.wait(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return imageFile;
	}
}
